/**
 *@file Vector.h
 *@author Ngoo Linghui
 *@date Wed 2021 Oct 20 10:48pm
 *@brief Implementation of vector
 **/

#include <algorithm>

template <typename Object>
class Vector
{
 public:
  explicit Vector( int initSize = 0 ) : theSize{ initSize },theCapacity{ initSize + SPARE_CAPACITY } //constructor: define a vector
    { objects = new Object[ theCapacity ]; }

    Vector ( const Vector & rhs ) : theSize{ rhs.theSize },theCapacity{ rhs.theCapacity}, objects{ nullptr }//Copy constructor
  {
    objects = new Object[ theCapacity ];
    for (int k = 0; k < theSize; ++k)
      objects[ k ] = rhs.objects[ k ]; 
  }

  Vector & operator= ( const Vector & rhs ) //operator overloading:copy the data of the vector.
  {
    Vector copy = rhs;
    std::swap(*this, copy );
    return *this;
  }

  ~Vector()
    {delete [] objects;}

  Vector( Vector && rhs ) : theSize{ rhs.theSize },theCapacity{ rhs.theCapacity },objects{ rhs.objects }
  {
    rhs.objects = nullptr;
    rhs.theSize = 0;
    rhs.theCapacity = 0;
  }

  Vector & operator= (Vector && rhs )
  {
    std::swap( theSize,rhs.theSize );
    std::swap( theCapacity, rhs.theCapacity );
    std::swap( objects, rhs.objects );

    return *this;
  }

  void resize( int newSize)//change the size of data 
  {
    if ( newSize > theCapacity )
      reverse( newSize*2);
    theSize = newSize;
  }

  void reverse( int newCapacity )//change the capacity of vector if there is not enough space
  {
    if( newCapacity < theSize )
      return;

    Object *newArray = new Object[ newCapacity ];
    for( int k = 0; k < theSize; k++)
      newArray[ k ] = std::move( objects[ k ] );

    theCapacity = newCapacity;
    std::swap( objects, newArray);
    delete [] newArray;
  }

  Object & operator[]( int index )//get the data of specific position
    {return objects[ index ];}
  const Object & operator[]( int index )const
  {return objects[ index ];}

  bool empty() const//determind whether the vector is empty
  {return size() ==0;}
  int size() const//the size of current data
  {return theSize;}
  int capacity() const//the capacity of current vector
  {return theCapacity;}

  void push_back( Object & x )//add an element at the end of the array
  {
    if( theSize == theCapacity)
      reverse( 2 * theCapacity + 1 );
    objects[ theSize++ ] = x;
  }

  void push_back( Object && x )
  {
    if( theSize == theCapacity )
      reverse( 2 * theCapacity + 1 );
    objects[ theSize++ ] = std::move(x);
  }

  void pop_back()//remove the last element of the array
  {
    --theSize;
  }

  const Object & back () const//get the last element of the array
  {
    return objects[ theSize - 1];
  }

  typedef Objects * iterator;
  typedef const Objects * const_iterator;

  iterator begin()//get the pointer of the first element
  {return &objects[ 0];}
  const_iterator begin() const
  {return &objects[ 0 ];}

  iterator end()
  {return &objects[ size() ];}//get the pointer of the last element
  const_iterator end() const
  {return &objects[ size() ];}

  static const int SPARE_CAPACITY = 16;

 private:
  int theSize;
  int theCapacity;
  Object * objects;

};
